#pragma once

#include "Event.h"

#include <list>
#include "Types.h"

namespace My {

class Control;
class Container;
class WindowTipCtrl;

typedef std::list<Control *>	ControlList;
typedef ControlList::iterator	ControlIndex;

class Control: public virtual EventListener
{
	friend class Container;
	friend class ClientDC;
private:
	Container *		m_pParent;
	ControlIndex	m_Index;
private:
	bool	m_Inside;
	// Dragging support
	bool	m_ButtonPressed;
	bool	m_Dragging;
	CPoint	m_DragStart;
protected:
	bool	m_PaintOutside;
public:
	virtual CPoint GetWindowOffset() const;
	virtual CRect GetWindowRect() const;
	virtual CWnd * GetWindow() const;  
	virtual WindowTipCtrl * GetHintWindow() const;
	virtual void Paint(CDC * pDC, const CRect & r);
public:
	Control();
	virtual ~Control();
public:
	Container * Parent() const
		{ return m_pParent; }
	ControlIndex Index() const
		{ return m_Index; }
	virtual CRect Bounds() const
		{ return CRect(0, 0, 0, 0); }
	virtual bool Visible() const
		{ return true; }
	virtual bool Enabled() const;
	CPoint Offset() const
		{ return Bounds().TopLeft(); }
	CSize Size() const
		{ return Bounds().Size(); }
	int Width() const
		{ return Size().cx; }
	int Height() const
		{ return Size().cy; }
	virtual CPoint ClientOrg() const
		{ return CPoint(0, 0); }
	virtual CSize ClientSize() const
		{ return Size(); }
	int ClientWidth() const
		{ return ClientSize().cx; }
	int ClientHeight() const
		{ return ClientSize().cy; }
	CRect ClientRect() const
		{ return CRect(CPoint(0, 0), ClientSize()); }
	bool Dragging() const
		{ return m_Dragging; }
	bool Hover() const
		{ return m_Inside; }
	bool PaintOutside() const
		{ return m_PaintOutside; }
	virtual bool CanGetFocus() const
		{ return false; }
	virtual String Hint() const;
	virtual const CFont * Font() const;
	void SelectFont(CDC * pDC) const; 
public:
	CPoint ClientToScreen(CPoint p) const;
	CPoint ScreenToClient(CPoint p) const;
	CPoint ClientToParent(CPoint p) const;
	CPoint ParentToClient(CPoint p) const;
	void InvalidateRect(const CRect & r);
	void Invalidate()
		{ InvalidateRect(ClientRect()); }
	void Update();
	void UpdateCursor();
	void UpdateHint();
	virtual void CaptureMouse();
	virtual void ReleaseMouse();
	virtual bool HasCapture() const;
	virtual void SetFocus();
	virtual bool HasFocus() const;
	virtual void ProcessEvent(Event & e);
	virtual void UpdateBounds();
	virtual void UpdateVisible();
	virtual void UpdateFont();
public:
	// handlers
	virtual void HandlePaint(CDC * pDC, const CRect & r) { }
	virtual void HandleActivate(bool active) { }
	virtual void HandleKeyDown(unsigned int key, unsigned int count, unsigned int flags) { }
	virtual void HandleKeyUp(unsigned int key, unsigned int count, unsigned int flags) { }
	virtual void HandleLeftDoubleClick(unsigned int flags, const CPoint & p) { }
	virtual void HandleLeftDown(unsigned int flags, const CPoint & p);
	virtual void HandleLeftUp(unsigned int flags, const CPoint & p);
	virtual void HandleMouseMove(unsigned int flags, const CPoint & p);
	virtual void HandleMouseEnter(unsigned int flags, const CPoint & p); 
	virtual void HandleMouseLeave();
	virtual void HandleRightDoubleClick(unsigned int flags, const CPoint & p) { }
	virtual void HandleRightDown(unsigned int flags, const CPoint & p) { }
	virtual void HandleRightUp(unsigned int flags, const CPoint & p) { }
	virtual bool HandleCursor(unsigned int flags, const CPoint & p) { return false; }
	virtual bool HandleDragStart(unsigned int flags, const CPoint & p0, const CPoint & p) { return false; }
	virtual void HandleDragEnd(unsigned int flags, const CPoint & p) { }
	virtual void HandleDragging(unsigned int flags, const CPoint & p) { }
	virtual void HandleUpdateUI() { }
	virtual void HandleFocus() { Invalidate(); }
	virtual void HandleUnfocus() { Invalidate(); }
	virtual void HandleFont();
};

bool ControlEnabled(const Control * pControl);

} // My
